package com.ridanlabs.professorwebsite.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.paypal.adaptive.api.requests.PaymentDetailsRequest;
import com.paypal.adaptive.api.requests.fnapi.SimplePay;
import com.paypal.adaptive.api.responses.PayResponse;
import com.paypal.adaptive.api.responses.PaymentDetailsResponse;
import com.paypal.adaptive.core.*;
import com.paypal.adaptive.exceptions.*;

public class PayPalRequests {
	private static final Logger LOG = LoggerFactory.getLogger(CourseController.class.getName());

	private static final Double CLASS_PRICE = 60.0;
	private static final ServiceEnvironment SERVICE_ENV = ServiceEnvironment.SANDBOX;
	private static final String APP_NAME = "Professor's Website";
	private static final CurrencyCodes CURRENCY_CODE = CurrencyCodes.USD;
	private static final String LANGUAGE = "en_US";
	private static final PaymentType PAYMENT_TYPE = PaymentType.SERVICE;
		
	public static PayResponse processSimplePayRequest(HttpServletRequest req, 
			HttpServletResponse resp, APICredential credentialObj) throws IOException {
		
		try {
			StringBuilder url = new StringBuilder();
			url.append(req.getRequestURL());
			String returnURL = url.toString() + "?return=1&action=pay&payKey=${payKey}";
			String cancelURL = url.toString() + "?action=pay&cancel=1";
			// ipn - Instant Payment Notification
			String ipnURL = url.toString() + "?action=ipn";
			
			SimplePay simplePay = new SimplePay();
			simplePay.setCancelUrl(cancelURL);
			simplePay.setReturnUrl(returnURL);
			simplePay.setCredentialObj(credentialObj);
			simplePay.setUserIp(req.getRemoteAddr());
			simplePay.setApplicationName(APP_NAME);
			simplePay.setCurrencyCode(CURRENCY_CODE);
			simplePay.setEnv(SERVICE_ENV);
			simplePay.setIpnURL(ipnURL);
			simplePay.setLanguage(LANGUAGE);
			simplePay.setMemo("");
			
			Receiver receiver = new Receiver();
			receiver.setAmount(CLASS_PRICE);
			receiver.setEmail(credentialObj.getAccountEmail());
			receiver.setPaymentType(PAYMENT_TYPE);
			simplePay.setReceiver(receiver);
			
			PayResponse payResponse = simplePay.makeRequest();
			return payResponse;
			
		}catch (IOException e) {
			LOG.error("Payment Failed w/ IOException");
		} catch (MissingAPICredentialsException e) {
			// No API Credential Object provided - log error
			e.printStackTrace();
			LOG.error("No APICredential object provided");
		} catch (InvalidAPICredentialsException e) {
			// invalid API Credentials provided - application error - log error
			e.printStackTrace();
			LOG.error("Invalid API Credentials " + e.getMissingCredentials());
		} catch (MissingParameterException e) {
			// missing parameter - log  error
			e.printStackTrace();
			LOG.error("Missing Parameter error: " + e.getParameterName());
		} catch (RequestFailureException e) {
			// HTTP Error - some connection issues ?
			e.printStackTrace();
			LOG.error("Request HTTP Error: " + e.getHTTP_RESPONSE_CODE());
		} catch (InvalidResponseDataException e) {
			// PayPal service error 
			// log error
			e.printStackTrace();
			LOG.error("Invalid Response Data from PayPal: \"" + e.getResponseData() + "\"");
		} catch (PayPalErrorException e) {
			// Request failed due to a Service/Application error
			e.printStackTrace();
			if(e.getResponseEnvelope().getAck() == AckCode.Failure){
				// log the error
				String errorMsg = "Received Failure from PayPay(ack) \nErrorData provided: " + e.getPayErrorList().toString();
				if(e.getPaymentExecStatus() != null){
					errorMsg.concat(" PaymentExecStatus: " + e.getPaymentExecStatus());
				}
				LOG.error(errorMsg);
				
			} else if(e.getResponseEnvelope().getAck() == AckCode.FailureWithWarning){
				// there is a warning - log it!
				LOG.error("Received Failure from PayPay(ack) \nErrorData provided: " + e.getPayErrorList().toString());
			}
		} catch (RequestAlreadyMadeException e) {
			// shouldn't occur - log the error
			e.printStackTrace();
			LOG.error("Request to send a request that has already been sent!");
		} catch (PaymentExecException e) {
			LOG.error("Failed Payment Request w/ PaymentExecStatus: " + e.getPaymentExecStatus().toString() + 
					"/nErrorData provided: " + e.getPayErrorList().toString());

		}catch (PaymentInCompleteException e){
			LOG.error("Incomplete Payment w/ PaymentExecStatus: " + e.getPaymentExecStatus().toString() + 
					"/nErrorData provided: " + e.getPayErrorList().toString());
			
		} catch (AuthorizationRequiredException e) {
			// redirect the user to PayPal for Authorization
			resp.sendRedirect(e.getAuthorizationUrl(SERVICE_ENV));
		}
		return null;
	}
	
	public static PaymentDetailsResponse processPaymentDetails(HttpServletResponse resp, 
			String payKey, String transactionId, String trackingId,
			APICredential credentialObj) throws IOException {

		try {
			PaymentDetailsRequest paymentDetailsRequest = new PaymentDetailsRequest(LANGUAGE, SERVICE_ENV);
			if(payKey != null)
				paymentDetailsRequest.setPayKey(payKey);
			if(transactionId != null)
				paymentDetailsRequest.setTransactionId(transactionId);
			if(trackingId != null)
				paymentDetailsRequest.setTrackingId(trackingId);
						
			PaymentDetailsResponse response = paymentDetailsRequest.execute(credentialObj);
			
			return response;
			
		} catch (IOException e) {
			return null;
		} catch (Exception e) {
			return null;
		}

	}
}
